#import "NetHackViewController.h"
#import "winiphone.h"

@implementation NetHackViewController

NetHackViewController *theNetHack;

#pragma Updating Views

- (void)updateMessageText {
	//NSLog(@"updateMessageText: %d %@", shouldClearMessage, messageText);
	if (hasMessageChanged) {
		messageLabel.text = messageText;
		[messageText release];
		messageText = [NSMutableString new];
		shouldClearMessage = YES;
	}
}

- (void)updateStatusText {
	if (hasStatusChanged) {
		statusLabel.text = statusText;
		[statusText release];
		statusText = [NSMutableString new];
		hasStatusChanged = NO;
	}
}

#pragma mark Turn Taking

- (void)doneWithTurn {
	NSThread *currentThread = [NSThread currentThread];
	whoseTurn = (currentThread == nethackThread) ? uiThread : nethackThread;

	[whoseTurnCondition signal];
	while (currentThread != whoseTurn) {
		[whoseTurnCondition wait];
	}
	
	//! don't like the nil check here
	if (currentThread == uiThread && tileView != nil) {
		[self updateMessageText];
		[tileView setNeedsDisplay];
		[self updateStatusText];
		
		if (shouldDelay) {
			//! during a delay, we should disable all input
			[self performSelector:@selector(doneWithTurn) withObject:nil
				afterDelay:0.05];
			shouldDelay = NO;
		}
		
		if (shouldShowMenu) {
			[self presentModalViewController:menuController animated:YES];
			shouldShowMenu = NO;
		}
	}
}

- (void)delayOutput {
	shouldDelay = YES;
	[self doneWithTurn];
}

#pragma mark Initialization

- (id)init {
	if (self = [super init]) {
		messageText = [NSMutableString new];
		statusText = [NSMutableString new];
		menuController = [MenuController new];
	}
	return self;
}

- (void)main {
	[whoseTurnCondition lock];
	
	// Each thread using Objective-C objects needs at least one autorelease pool.
	//! We need to make sure that we actually release the objects sometimes.
	NSAutoreleasePool *pool = [NSAutoreleasePool new];
	mainNetHack();
	[pool release];
}

- (void)start {
	whoseTurnCondition = [NSCondition new];
	[whoseTurnCondition setName:@"whoseTurnCondition"];

	uiThread = [[NSThread currentThread] retain];
	nethackThread = [[NSThread alloc] initWithTarget:self
		selector:@selector(main) object:nil];
	[nethackThread setName:@"nethackThread"];
	
	[nethackThread start];
	[whoseTurnCondition lock];
	[self doneWithTurn];	
}

+ (NetHackViewController *)nethack {
	if (theNetHack == nil) {
		theNetHack = [NetHackViewController new];
		[theNetHack start];
	}
	return theNetHack;
}

- (void)loadView {
	[super loadView];
    
    [self.view setBackgroundColor: [UIColor whiteColor]];
    
    //tile view
    {
        CGRect frame= [[UIScreen mainScreen] bounds];
        tileView= [[TileView alloc] initWithFrame: frame];
        tileView.userInteractionEnabled= FALSE;
        [self.view addSubview: tileView];
    }
    

	// Keyboard
    {
        keyboardTextField = [UITextField new];
        keyboardTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
        keyboardTextField.autocorrectionType = UITextAutocorrectionTypeNo;
        keyboardTextField.keyboardType = UIKeyboardTypeASCIICapable;
        keyboardTextField.delegate = self;
        [self.view addSubview:keyboardTextField];
    }
    
	// Message Text
    {
        const CGFloat messageLabelHeight = 30.0;
        CGRect frame= CGRectMake(0.0, 0.0, [[UIScreen mainScreen] bounds].size.width, messageLabelHeight);
        UIViewAutoresizing mask= UIViewAutoresizingFlexibleBottomMargin |  UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        messageLabel = [[UILabel alloc] initWithFrame:frame];
        messageLabel.textColor = [UIColor greenColor];
        messageLabel.backgroundColor = [UIColor clearColor];
        messageLabel.font = [UIFont fontWithName:@"Courier-Bold" size:10];
        messageLabel.autoresizingMask= mask;
        messageLabel.lineBreakMode=  UILineBreakModeWordWrap;
        messageLabel.numberOfLines= 3;
        messageLabel.baselineAdjustment= UIBaselineAdjustmentNone;
        [self.view addSubview:messageLabel];
    }
	
    // Status Text
    {
        const CGFloat statusLabelHeight = 65.0;
        CGRect frame= CGRectMake(0.0, [[UIScreen mainScreen] bounds].size.height-statusLabelHeight, [[UIScreen mainScreen] bounds].size.width, statusLabelHeight);
        UIViewAutoresizing mask= UIViewAutoresizingFlexibleTopMargin |  UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        statusLabel = [[UILabel alloc] initWithFrame:frame];
        statusLabel.backgroundColor = [UIColor clearColor];
        statusLabel.textColor = [UIColor orangeColor];
        statusLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:10];
        statusLabel.autoresizingMask= mask;
        statusLabel.lineBreakMode=  UILineBreakModeWordWrap;
        statusLabel.numberOfLines= 3;
        statusLabel.baselineAdjustment= UIBaselineAdjustmentNone;        
        [self.view addSubview:statusLabel];
    }

    { // Action Control
        UILabel *actionLabel= [[UILabel alloc] initWithFrame: CGRectMake(15.0,self.view.center.y-200.0,self.view.bounds.size.width-30.0,40.0)];
        actionLabel.backgroundColor= [UIColor clearColor];
        actionLabel.textColor= [UIColor whiteColor];
        actionLabel.text= @"";
        actionLabel.shadowColor= [UIColor grayColor];
        actionLabel.shadowOffset= CGSizeMake(1.0,1.0);
        actionLabel.textAlignment= UITextAlignmentCenter;
        actionLabel.font= [UIFont fontWithName: @"Verdana" size: 20.0];
        actionLabel.numberOfLines= 1;
        actionLabel.minimumFontSize= 10.0;
        actionLabel.adjustsFontSizeToFitWidth= TRUE;

        [self.view addSubview: actionLabel];
    
    
        NSString *path= [[[NSBundle mainBundle] resourcePath] stringByAppendingString: @"/ActionControl.plist"];
        NSLog(@"reading control from path %@",path);
        NSDictionary *dict= [[NSDictionary alloc] initWithContentsOfFile: path];
    
        CGRect frame= CGRectMake(self.view.center.x-150.0,self.view.center.y-150.0,300.0,300.0);
        actionControl= [[ActionControl alloc] initWithFrame: frame andDictionary: dict];
        actionControl.descriptionLabel= actionLabel;
        [self.view addSubview: actionControl];
        [actionControl setController: self];


    }
    
	[self updateMessageText];
	[self updateStatusText];
}

- (void)viewWillAppear:(BOOL)animated {
//	[keyboardTextField becomeFirstResponder];
}

- (void)dealloc {
	[whoseTurnCondition release];
	[uiThread release];
	[nethackThread release];
	
	[keyboardTextField release];
	[messageLabel release];
	[tileView release];
	[statusLabel release];
	
	[messageText release];
	[statusText release];
	
	[menuController release];
	
	[super dealloc];
}

#pragma mark Windows

typedef enum {
	NetHackWindowMessage = (1 << 0),
	NetHackWindowStatus = (1 << 1),
	NetHackWindowMap = (1 << 2),
	NetHackWindowMenu = (1 << 3),
	NetHackWindowText = (1 << 4),
} NetHackWindows;

- (NetHackWindows)createWindow:(int)windowType {
	NetHackWindows wid = (1 << (windowType - 1));
	if (createdWindows & wid) {
		//NSLog(@"CREATED EXTRA: %d", windowId);
		//! we appear to create extra map windows
	} else {
		createdWindows |= wid;
		//! we don't need to watch this anymore
		//NSLog(@"createWindow: %d %d", windowId, windowType);
	}
	return wid;
}

- (void)clearWindow:(NetHackWindows)wid {
	if (wid == NetHackWindowMessage) {
		shouldClearMessage = YES;
	} else if (wid == NetHackWindowMap) {
		clearTiles();
	} else {
		NSLog(@"clearWindow %d", wid);
	}
}

#pragma mark Input

- (int)getCharacter {
	[self doneWithTurn];
	return character;
}

- (void)putCharacter:(char)c {
	character = c;
	[self doneWithTurn];
}

#pragma mark Output

- (void)putString:(NSString *)text toWindow:(NetHackWindows)wid withAttributes:(int)attr {
	if (wid == NetHackWindowMessage) {
		[messageText appendString:text];
		[messageText appendString:@"\n"];
		hasMessageChanged = YES;
		//NSLog(@"put message: %@", messageText);
	} else if (wid == NetHackWindowStatus) {
		[statusText appendString:text];
		[statusText appendString:@"\n"];
		hasStatusChanged = YES;
		//NSLog(@"put status: %@", text);
	} else if (wid == NetHackWindowMenu) {
		//! ignore for the moment
	} else {
		//! handle other windows
		NSLog(@"putString: %@", text);
	}
}

#pragma mark Menu

- (void)clearMenu {
	[menuController clear];
}

- (void)addMenuItemWithText:(NSString *)text tile:(UIImage *)tile {
	[menuController addMenuItemWithText:text tile:tile];
}

- (void)showMenu {
	shouldShowMenu = YES;
}

- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) orientation
{
    self.view.autoresizesSubviews= TRUE;
    return TRUE;
}



#pragma mark UITextFieldDelegate

- (BOOL)textField:(UITextField *)textField
		shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
	if (string.length > 0) {
		char c = *[string cStringUsingEncoding:NSStringEncodingConversionAllowLossy];
		//NSLog(@"ENTERED: %c", c);
		[self putCharacter:c];
	}
	return NO;
}




 
#pragma mark -

#pragma mark C Functions

const char *getAbsolutePath(const char *filename) {
	NSString *fileNameString = [NSString stringWithCString:filename];
	NSString *path = [[NSBundle mainBundle]
		pathForResource:fileNameString ofType:@""];
	const char *pathCString = [path
		cStringUsingEncoding:NSStringEncodingConversionAllowLossy];
	return pathCString;
}

UIImage *imageForTileIndex(short tileIndex) {
	static CGImageRef tiles;

	if (tileIndex == -1) {
		return nil;
	}
	
	if (tiles == nil) {
		UIImage *tilesImage = [UIImage imageNamed:@"nhtiles.png"];
		tiles = CGImageRetain(tilesImage.CGImage);
	}
	
	int x = tileIndex % TILES_PER_ROW;
	int y = tileIndex / TILES_PER_ROW;
	
	CGRect rect = CGRectMake(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
	CGImageRef tile = CGImageCreateWithImageInRect(tiles, rect);
	
	return [UIImage imageWithCGImage:tile];
}

extern short glyph2tile[];
short levelTiles[ROWNO][COLNO];

void clearTiles() {
	for (int r = 0; r < ROWNO; ++r) {
		for (int c = 0; c < COLNO; ++c) {
			levelTiles[r][c] = -1;
		}
	}
}

short tileAt(short x, short y) {
	if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO) {
		return -1;
	}
	return levelTiles[y][x];
}

int getCharacter() {
	return [theNetHack getCharacter];
}

void putString(winid wid, int attr, const char *text) {
	[theNetHack putString:[NSString stringWithCString:text]
		toWindow:wid withAttributes:attr];
}

void printGlyph(int x, int y, int glyph) {
	short tile = glyph2tile[glyph];
	levelTiles[y][x] = tile;
}

void rawPrint(const char *text) {
	[theNetHack putString:[NSString stringWithCString:text]
		toWindow:NetHackWindowMessage withAttributes:0];
}

char ynFunction(const char *question, const char *choices, int defaultChoice) {
	NSString *text = (choices == nil) ?
		[NSString stringWithCString:question] :
		[NSString stringWithFormat:@"%s %s", question, choices];
	[theNetHack putString:text toWindow:NetHackWindowMessage withAttributes:0];
	char c = getCharacter();
	//! see window.doc for some rules regarding the return value
	return c;
}

winid createWindow(int windowType) {
	return [theNetHack createWindow:windowType];
}

void clearWindow(winid wid) {
	[theNetHack clearWindow:wid];
}

void displayWindow(winid wid) {
	//NSLog(@"displayWindow %d", wid);
	//! don't need to do anything for 1, 2, and 4 windows
}

void destroyWindow(winid wid) {
	//NSLog(@"destroyWindow %d", wid);
	//! we only seem to destroy 8 (NetHackWindowMenu) windows
}

void delayOutput() {
	[theNetHack delayOutput];
}

void startMenu() {
	[theNetHack clearMenu];
}

void addMenuItem(int glyph, const char *item) {
	NSString *text = [NSString stringWithCString:item];
	short tileIndex = (glyph == NO_GLYPH) ? -1 : glyph2tile[glyph];
	UIImage *tile = imageForTileIndex(tileIndex);
	[theNetHack addMenuItemWithText:text tile:tile];
}

void endMenu(const char *prompt) {
	//!! use prompt
	[theNetHack showMenu];
}



@end
